﻿using SQX.DataModel;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

namespace SQX.ViewModel
{
    public abstract class ViewModelBasic : INotifyPropertyChanged, IDisposable
    {
        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string PropertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null)
            {
                handler(this, new PropertyChangedEventArgs(PropertyName));
            }
        }

        public DeferredAction DeferredAct { get; set; }

        public void Dispose()
        {
            Dispose(true);
        }

        protected virtual void Dispose(bool isDisposed)
        {
            if (isDisposed)
            {
                GC.SuppressFinalize(this);
                GC.Collect();
            }
        }
    }
    public abstract class QueryViewModelBasic : ViewModelBasic
    {
        protected Query activeQuery;
        protected string modelName;

        public QueryViewModelBasic()
        {
            QueryHelpList = new ObservableCollection<LanguageObject>();
            QueryCollection = new ObservableCollection<Query>();
        }

        public ObservableCollection<LanguageObject> QueryHelpList { get; set; }
        public SyntaxMarkup Markup { get; set; }

        public Query ActiveQuery 
        { 
            get { return activeQuery; }
            set { activeQuery = value; OnPropertyChanged("ActiveQuery"); }
        }

        public ObservableCollection<Query> QueryCollection { get; set; }

        public void AddQuery(string QueryText, Service.SourceType QueryType, object Connection)
        {
            switch (QueryType)
            {
                case Service.SourceType.SourceOLAP:
                    var query = new MDXQuery("Query " + Guid.NewGuid().ToString(), QueryText, Connection);
                    this.ActiveQuery = query;
                    QueryCollection.Add(query);
                    break;
                case Service.SourceType.SourceSQL:
                    var sqlQuery = new SqlQuery("Query " + Guid.NewGuid().ToString(), QueryText, Connection);
                    this.ActiveQuery = sqlQuery;
                    QueryCollection.Add(sqlQuery);
                    break;
            }
        }

        public string ModelName
        {
            get { return modelName; }
        }

    }

    public class AxisConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return System.Convert.ToInt32(value) - 0.17 * System.Convert.ToInt32(value);
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class RelativeAxisConverter : IMultiValueConverter
    {

        public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (double)values[0] - (double)values[1]-50;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class SavedStatusToColorConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (bool)value == true ? new SolidColorBrush(Colors.LightSkyBlue) : new SolidColorBrush(Color.FromRgb(211, 211, 211));
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class ItemCountToVisibilityConverter : IValueConverter
    {

        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            return (int)value > 0 ? Visibility.Visible : Visibility.Hidden;
        }

        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }

    public class ObjectExplorerTemplateSelector : DataTemplateSelector
    {
        public DataTemplate serverTemplate { get; set; }
        public DataTemplate sqlServerTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item,
          DependencyObject container)
        {
            switch (item.GetType().Name)
            {
                case "AdomdServer":
                    return serverTemplate;
                case "SqlServer":
                    return sqlServerTemplate;
                default:
                    return null;
            }
        }
    }

    public class ToolTipTemplateSelector : DataTemplateSelector
    {
        public DataTemplate structureTemplate { get; set; }
        public DataTemplate syntaxTemplate { get; set; }
        public DataTemplate functionTemplate { get; set; }

        public override DataTemplate SelectTemplate(object item,
          DependencyObject container)
        {
            switch (item.GetType().Name)
            {
                case "DatabaseElement":
                    return structureTemplate;
                case "LanguageReserved":
                    return syntaxTemplate;
                case "LanguageFunction":
                    return functionTemplate;
                default:
                    return null;
            }
        }
    }

    public class RichTextBoxHelper : DependencyObject
    {

        public static DependencyProperty DocumentTextProperty =
            DependencyProperty.RegisterAttached(
            "DocumentText",
            typeof(string),
            typeof(RichTextBoxHelper),
            new FrameworkPropertyMetadata(OnDocumentTextChanged));

        public static string GetDocumentText(FrameworkElement fe)
        {
            return (string)fe.GetValue(DocumentTextProperty);
        }

        public static void SetDocumentText(FrameworkElement fe, string value)
        {
            fe.SetValue(DocumentTextProperty, value);
        }

        // possible fix RTB text property missing, with DP : add text_input event and rebind!
        private static void OnDocumentTextChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var box = (RichTextBox)obj;

            if (e.NewValue.ToString() == "")
            {
                box.PreviewTextInput += box_PreviewTextInput;
                box.PreviewKeyUp += box_PreviewKeyUp;
            }
        }

        private static void box_PreviewKeyUp(object sender, KeyEventArgs e)
        {
            var box = (sender as RichTextBox);
            if (e.Key == Key.Back)
            {
                var text = (box.GetBindingExpression(DocumentTextProperty).DataItem as Query).Text;
                if (text.Length >=1) (box.GetBindingExpression(DocumentTextProperty).DataItem as Query).Text = text.Substring(0, text.Length - 1);
            }
        }

        private static void box_PreviewTextInput(object sender, TextCompositionEventArgs e)
        {
            UpdateText((sender as RichTextBox), e.Text);
        }

        private static void UpdateText(RichTextBox box, string element)
        {
            if (box.Document != null)
            {
                var text = (box.GetBindingExpression(DocumentTextProperty).DataItem as Query).Text;
                (box.GetBindingExpression(DocumentTextProperty).DataItem as Query).Text = text + element;
            }
        }
    }

    // source : http://www.codeproject.com/Articles/32426/Deferring-ListCollectionView-filter-updates-for-a
    public class DeferredAction : IDisposable
    {
        private Timer timer = null;

        private DeferredAction(Action action)
        {
            this.timer = new Timer(new TimerCallback(delegate
            {
                Application.Current.Dispatcher.Invoke(action);
            }));
        }

        /// <summary>
        /// Creates a new DeferredAction.
        /// </summary>
        /// <param name="action">
        /// The action that will be deferred. It is not performed until 
        /// after <see cref="Defer"/> is called.
        /// </param>
        public static DeferredAction Create(Action action)
        {
            if (action == null)
            {
                throw new ArgumentNullException("action");
            }

            return new DeferredAction(action);
        }

        /// <summary>
        /// Defers performing the action until after time elapses. 
        /// Repeated calls will reschedule the action
        /// if it has not already been performed.
        /// </summary>
        /// <param name="delay">
        /// The amount of time to wait before performing the action.
        /// </param>
        public void Defer(TimeSpan delay)
        {
            // Fire action when time elapses (with no subsequent calls).
            this.timer.Change(delay, TimeSpan.FromMilliseconds(-1));
        }



        public void Dispose()
        {
            this.Dispose(false);
        }

        protected virtual void Dispose(bool isDisposed)
        {
            if (!isDisposed)
            {
                this.timer.Dispose();
                GC.SuppressFinalize(this);
                GC.Collect();
            }
        }
    }

    public static class Command
    {
        public static RoutedCommand RTBUndo = new RoutedCommand();
        public static RoutedCommand QuerySave = new RoutedCommand();
    }
}
